﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Microsoft.Xna.Framework.Content;
using Microsoft.Xna.Framework.Content.Pipeline.Serialization.Intermediate;

namespace Baddies.Utils
{
    /// <summary>
    /// Custom serializer for the SharedResourceDictionary class.
    /// Use it to serialize all values as references.
    /// </summary>
    /// <typeparam name="T">Type of key in the SharedResourceDictionary.</typeparam>
    /// <typeparam name="K">Type of value in the SharedResourceDictionary.</typeparam>
    [ContentTypeSerializer]
    public class SharedResourceDictionarySerializer<T, K> : ContentTypeSerializer<SharedResourceDictionary<T, K>>
    {
        /// <summary>
        /// Custom format for each pair in the Dictionary.
        /// </summary>
        private static ContentSerializerAttribute itemFormat = new ContentSerializerAttribute()
        {
            ElementName = "Item"
        };

        /// <summary>
        /// Format for the Key of each item.
        /// </summary>
        private static ContentSerializerAttribute keyFormat = new ContentSerializerAttribute()
        {
            ElementName = "Key"
        };

        /// <summary>
        /// Format for the Value of each item.
        /// </summary>
        private static ContentSerializerAttribute valueFormat = new ContentSerializerAttribute()
        {
            ElementName = "Value"
        };

        /// <summary>
        /// Serializes the SharedResourceDictionary.
        /// </summary>
        /// <param name="output">Writer to serialize to.</param>
        /// <param name="value">Dictionary to serialize.</param>
        /// <param name="format">Format options for serialization.</param>
        protected override void Serialize(
            IntermediateWriter output,
            SharedResourceDictionary<T, K> value,
            ContentSerializerAttribute format)
        {
            foreach (KeyValuePair<T, K> item in value)
            {
                output.Xml.WriteStartElement(itemFormat.ElementName);
                output.WriteObject(item.Key, keyFormat);
                output.WriteSharedResource(item.Value, valueFormat);
                output.Xml.WriteEndElement();
            }
        }

        /// <summary>
        /// Deserializes the SharedResourceDictionary.
        /// </summary>
        /// <param name="input">Reader with the xml data.</param>
        /// <param name="format">Format options of the data.</param>
        /// <param name="existingInstance">SharedResourceDictionary where we put the deserialized data.</param>
        /// <returns>The deserialized SharedResourceDictionary.</returns>
        protected override SharedResourceDictionary<T, K> Deserialize(
            IntermediateReader input,
            ContentSerializerAttribute format,
            SharedResourceDictionary<T, K> existingInstance)
        {
            if (existingInstance == null)
            {
                existingInstance = new SharedResourceDictionary<T, K>();
            }

            while (input.MoveToElement(itemFormat.ElementName))
            {
                T key;

                input.Xml.ReadToDescendant(keyFormat.ElementName);
                key = input.ReadObject<T>(keyFormat);
                input.Xml.ReadToNextSibling(valueFormat.ElementName);
                input.ReadSharedResource<K>(
                    valueFormat, 
                    (K value) =>
                    {
                        existingInstance.Add(key, value);
                    });
                input.Xml.ReadEndElement();
            }

            return existingInstance;
        }
    }
}
